#include <iostream>

// 1. 预处理器替换可能导致意外
// 编译器是看不到#define的东西的，会被预处理器处理
#define MULTIPLY(a, b) a *b
int result = MULTIPLY(3 + 2, 4); // 展开为: 3 + 2 * 4 = 11，而不是20

// 2. 宏不遵守作用域规则
#define TEMP temp // 全局替换，可能影响其他代码

// 3. 宏没有类型检查
#define SIZE 1024.5 // 是整数还是浮点数？

// 4. 调试困难
// 宏在预处理阶段就被替换，调试器看不到原始定义

// 1.使用const代替#define
// 不好的方式
// #define PI 3.14159
// #define MAX_BUFFER_SIZE 1024

// 好的方式
const double PI = 3.14159;
const int MAX_BUFFER_SIZE = 1024;

// 更好的方式
// const会进入符号表，便于调试
// const有类型信息，更安全
// const可以限定作用域
// const可以用于更复杂的类型
namespace Constants
{
    constexpr double PI = 3.14159;
    constexpr int MAX_BUFFER_SIZE = 1024;
}

class Wdiget
{
private:
    // 类内常量
    static const int MIN_SIZE = 16;
    static constexpr double MAX_BUFFER_SIZE = 1024; // 更推荐
};

// 2.使用enum替换#define
// enum提供类型安全
// enum可以限定作用域
// enum不会占用内存（除非取地址）
// enum hack可以在类中定义常量而不占用内存
// 不好的方式
// #define RED     0
// #define GREEN   1
// #define BLUE    2

// 好的方式普通枚举
enum Color
{
    RED = 0,
    GREEN = 1,
    BLUE = 2
};

// 更好的方式 强类型枚举
enum class Color : uint8_t
{
    RED = 0,
    GREEN = 1,
    BLUE = 2
};

// 特殊用法
class GamePlayer
{
private:
    enum
    {
        NUM_TURNS = 5
    };
};

// 3.用inline替换#define
// 不好的方式
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

// 宏函数的问题
void question()
{
    int i = 5;
    int j = SQUARE(i++); // i被增加两次
}

// 好的方式
template <typename T>
inline T square(T x)
{
    return x * x;
}

template <typename T>
inline T max(const T &a, const T &b)
{
    return a > b ? a : b;
}

// modern
constexpr auto square = [](auto x)
{
    return x * x;
};
